import * as _ from 'lodash';
import * as React from 'react';
import shallowEq from 'shallow-eq';
import { Props, State } from './helper.type';
import { Toast } from 'antd-mobile-v2';
import { WrapRoot, findTemplateChilds } from './utils';
class Empty extends React.Component<any, any> {
  static defaultProps = {
    editSetting: {
      key: 'gaea-buildin-placeholder',
      editors: []
    }
  };

  render() {
    return (
      <div style={{ lineHeight: '20px' }}>
        <div
          style={{
            width: '100px',
            display: 'inline-block',
            textAlign: 'right',
            marginRight: '15px',
            marginBottom: '8px'
          }}
        >
          {this.props.name}
        </div>
        占位～～～
      </div>
    );
  }
}

// 对没有提供对应处理组件的控件组的统一处理
class EmptyContainer extends React.Component<any, any> {
  static defaultProps = {
    editSetting: {
      key: 'gaea-buildin-container',
      editors: []
    }
  };

  render() {
    return <>{this.props.children}</>;
  }
}

class RenderHelper extends React.Component<Props, State> {
  public static defaultProps = new Props();
  public state = new State();

  // 内部组件实例
  public wrappedInstance: React.ReactInstance;

  private instanceInfo: any;
  private childHandlers: { [index: string]: any } = {};
  private componentClass: React.ComponentClass<any>;

  public shouldComponentUpdate(nextProps: Props, nextState: State) {
    // state 浅相等，排除 data。并且 data 深相等，认为数据没变
    if (
      !shallowEq(this.state, nextState, ['data']) ||
      !_.isEqual(this.state.data, nextState.data)
    ) {
      return true;
    }

    // props 浅相等，排除 data。并且 data 深相等，认为数据没变
    if (
      !shallowEq(this.props, nextProps, ['data']) ||
      !_.isEqual(this.props.data, nextProps.data)
    ) {
      return true;
    }

    // 对比当前code的数据和viewport里面的formValues code数据是否一致，如果不一致则更新
    if (
      this.props.instanceKey &&
      (!shallowEq(
        this.props.viewport?.prevParams,
        this.props.viewport?.params,
        [this.props.instanceKey]
      ) ||
        !_.isEqual(
          this.props.viewport?.prevParams?.[this.props.instanceKey],
          this.props.viewport?.params?.[this.props.instanceKey]
        ))
    ) {
      return true;
    }

    return false;
  }

  public UNSAFE_componentWillMount() {
    // 从 store 找到自己信息
    this.instanceInfo = this.props.viewport.instances.get(
      this.props.instanceKey
    );
    if (!this.instanceInfo) {
      return;
    }

    this.props.viewport?.event.on('GaeaPropsChange', this.changeProps);

    // 获取当前要渲染的组件 class
    const tmp = this.props.viewport.componentClasses.get(
      this.instanceInfo.gaeaKey
    );
    if (tmp) {
      this.componentClass = tmp;
    }
    if (!this.componentClass) {
      // TODO 后期加了日期区间组件的编辑，isBasicGroup这个判读可以去除
      if (
        (this.instanceInfo && this.instanceInfo.isContainer) ||
        this.instanceInfo.isGroup ||
        this.instanceInfo.isBasicGroup
      ) {
        this.componentClass = EmptyContainer;
      } else {
        this.componentClass = Empty;
      }
    }
    // 执行 trigger -> init 事件
    if (this.instanceInfo && this.instanceInfo.data?.events) {
      this.instanceInfo.data.events.forEach((event: any) => {
        switch (event.trigger.type) {
          case 'init':
            this.runEvent(event);
            break;
          case 'subscribe':
            this.props.viewport?.event.on(
              event.trigger.name,
              this.handleSubscribe,
              event,
            );
            break;
        }
      });
    }
  }

  private changeProps = (_a: any, propsMaps?: IterateAny) => {
    if (!this.props.instanceKey) return;
    if (!propsMaps) return;
    if (!propsMaps[this.props.instanceKey]) return;
    if (propsMaps[this.props.instanceKey]) {
      const propsChanged = propsMaps[this.props.instanceKey];
      if (propsChanged.value) {
        this.props.form?.setFieldsValue({
          [this.props.instanceKey]: propsChanged.value
        });
      }
      const originPropsChanged =
        _.get(this.instanceInfo, 'data.propsChanged') || {};
      _.set(this.instanceInfo, 'data.propsChanged', {
        ...originPropsChanged,
        ...propsChanged
      });
    }
  };

  private getProps(instanceKey?: string) {
    if (!instanceKey) return;
    const instanceInfo = this.props.viewport?.instances.get(instanceKey);
    if (!instanceInfo) return;

    const props: any = {};

    // 将回调事件添加到 props 中
    const functionMap = this.getSelfFunctionMap();
    functionMap.forEach((value: any, key: string) => {
      props[key] = props[`${key}FormOrigin`] = (...args: any[]) => {
        value.forEach((eachValue: any) => {
          this.runEvent.call(this, eachValue, ...args);
        });
      };
    });

    // render 模式就是 preview 模式
    props.isPreview = true;

    props.ref = (ref: React.ReactInstance) => {
      this.wrappedInstance = ref;
    };

    // 注入 props
    _.merge(props, _.get(instanceInfo, 'data.props') || {});
    _.merge(props, _.get(instanceInfo, 'data.propsChanged') || {});
    _.merge(props, {
      error: this.props.form?.getFieldError(props.code),
      onErrorClick: () => {
        this.onErrorClick(props.code);
      }
    });

    // 实装变量设置
    // if (instanceInfo.variables) {
    //   Object.keys(instanceInfo.variables).forEach((realField: string) => {
    //     const variable = instanceInfo.variables[realField];
    //     switch (variable.type) {
    //       case 'sibling':
    //         // 同级传参，从 props 获取
    //         _.set(props, realField, this.props.data[variable.key]);
    //         break;
    //     }
    //   });
    // }

    return props;
  }

  public componentWillUnmount() {
    if (this.instanceInfo && this.instanceInfo.data.events) {
      this.instanceInfo.data.events.forEach((event: any) => {
        if (event.trigger.type === 'subscribe') {
          this.props.viewport.event.off(
            event.trigger.name,
            this.handleSubscribe
          );
        }
      });
    }
  }

  public render() {
    if (!this.instanceInfo) {
      return null;
    }
    // 子元素
    let childs: Array<React.ReactElement<any>> | null = null;

    // 是否可以有子元素 容器和组以生成好的children传入进去，明细以childTemplate的方式作为模板传进去
    if (
      this.componentClass &&
      (this.componentClass.defaultProps?.editSetting.isContainer ||
        this.componentClass.defaultProps?.editSetting.isGroup ||
        this.componentClass.defaultProps?.editSetting.isBasicGroup ||
        this.componentClass == EmptyContainer) &&
      this.instanceInfo.childs
    ) {
      childs = this.instanceInfo.childs.map((childKey: any) => {
        const childInstance = this.props.viewport?.instances.get(childKey);
        const childProps: any = {
          key: childKey,
          viewport: this.props.viewport,
          instanceKey: childKey,
          form: this.props.form,
          renderMode: this.props.renderMode,
          onCallback: this.handleCallback,
          rows: this.props.rows,
          layout: this.props.layout,
          disabled: this.props.disabled
        };
        // 注入 props
        _.merge(childProps, _.get(childInstance, 'data.props') || {});
        if (childInstance && childInstance.variables) {
          childProps.data = {};
          Object.keys(childInstance.variables).forEach((realField: string) => {
            const variable = childInstance.variables[realField];
            childProps.data[variable.key] = this.state.data?.[variable.key];
          });
        }

        return React.createElement(RenderHelper, childProps);
      });
    }

    let childTemplate;
    if (
      this.componentClass.defaultProps?.editSetting.childExpressWay ===
      'template'
    ) {
      const childIds = this.props.viewport?.instances.get(this.props.instanceKey).childs;
      const childObj: IterateAny = {};
      findTemplateChilds(childObj, this.props.viewport?.instances, childIds);
      childTemplate = WrapRoot(childObj, childIds);
    }
    let props = this.getProps(this.props.instanceKey);
    if (childTemplate) {
      props = { childTemplate, ...props };
    }
    let setCardMinHeight = {};
    if (this.componentClass.defaultProps?.style?.minHeight && this.componentClass.defaultProps?.editSetting.key === 'gaea-card') {
      setCardMinHeight = { style: { minHeight: 1 } };
    }
    return React.createElement(
      // 使用WrapFormItem,使详情时没有定义的组件样式正常显示,但是申请时表单项会多加一层form-item
      this.componentClass,
      _.merge(
        {
          // instanceKey: this.props.instanceKey,
          layout: this.props.layout,
          rows: this.props.rows,
          form: this.props.form,
          formValues: this.props.viewport?.params?.formValues,
          renderMode: this.props.renderMode,
          setChildHandlers: this.setChildHandlers,
          GaeaOnPropsCallback: this.gaeaOnPropsCallback
        },
        this.componentClass.defaultProps,
        setCardMinHeight,
        { disabled: this.props.disabled },
        props
      ),
      childs
    );
  }
  // 改变其他组件的props 通过事件桥来进行
  public gaeaOnPropsCallback = (options: IterateAny) => {
    this.props.viewport?.event.emit('GaeaPropsChange', options);
  };


  public setChildHandlers = (handlers: IterateAny) => {
    this.childHandlers = handlers;
  };

  private onErrorClick = (code: string) => {
    Toast.info(this.props.form?.getFieldError(code)[0]);
  };

  /**
   * 子元素触发的回调，用来触发同层级传值的事件
   */
  private handleCallback = (data: any) => {
    this.setState((state) => {
      return {
        ...state,
        data: {
          ...state.data,
          [data.name]: data.value
        }
      };
    });
  };

  /**
   * 监听事件执行了
   */
  private handleSubscribe = (context: any, ...values: any) => {
    this.runEvent(context, ...values);
  };

  /**
   * 执行事件
   */
  private runEvent = (event: any, ...values: any[]) => {
    switch (event.action.type) {
      case 'none':
        break;
      case 'passingSiblingNodes':
        if (!event.actionData || !event.actionData.data) {
          return;
        }
        event.actionData.data.forEach((data: any, index: number) => {
          if (typeof this.props.onCallback === 'function') {
            // 通知父级，让父级刷新
            this.props.onCallback({
              name: data.name,
              value: values[index]
            });
          }
        });
        break;
      case 'jump':
        window.open(event.action.url);
        break;
      case 'emit':
        this.props.viewport?.event.emit(event.action.name, ...values);
        break;
      case 'childHandler':
        if (this.childHandlers) {
          this.childHandlers[event.action.field]?.call(null, ...values);
        }
        break;
      default:
    }
  };

  /**
   * 返回调用自己的方法的 key -> Array<value>
   */
  private getSelfFunctionMap = () => {
    const functionMap = new Map();
    if (this.instanceInfo.data.events) {
      this.instanceInfo.data.events.forEach((event: any) => {
        if (event.trigger.type === 'callback') {
          if (functionMap.has(event.trigger.field)) {
            const functionList = functionMap.get(event.trigger.field);
            functionList.push(event);
            functionMap.set(event.trigger.field, functionList);
          } else {
            functionMap.set(event.trigger.field, [event]);
          }
        }
      });
    }
    return functionMap;
  };
}

export default RenderHelper;
